
#include "stdafx.h"
#include "Win32.System.User.h"

// -----------------------------------------------------------------------------

namespace Kif
{
namespace Win32
{
namespace System
{

// -----------------------------------------------------------------------------
// Initialize / Release resources...

/// <summary>Release allocated resources</summary>
void SystemUser::Dispose()
{
   if (hToken != INVALID_HANDLE_VALUE)
      CloseHandle(hToken);
   hToken = INVALID_HANDLE_VALUE;
}  // end of Dispose

/// <summary>Initialize the SystemUser (ctor)</summary>
SystemUser::SystemUser()
{
   hToken = INVALID_HANDLE_VALUE;
}  // end of SystemUser (ctor)

/// <summary>Clean-Up and Release allocated resources</summary>
SystemUser::~SystemUser()
{
   Dispose();
}  // end of SystemUser (ctor)

// -----------------------------------------------------------------------------

/// <summary>Get current user token</summary>
bool SystemUser::GetCurrentUserToken()
{
   bool done = false;
   // the process may be running as a different user, therefore we don't have
   // access to it, so we need to enable the debug privilege...
   // TODO: implement AdjustTokenPrivileges(); to get SE_DBUG_NAME

   // try to get the token for the current user
   BOOL f = OpenProcessToken(GetCurrentProcess(),TOKEN_READ,&hToken);
   if (f && hToken)
      done = true;

   // we need to restore the priviliges back to the starting point...
   // TODO: reestabish the priviliges as needed
   return done;
}  // end of GetCurrentUserToken

// -----------------------------------------------------------------------------

/// <summary>See if the current process is elevated...</summary>
/// <param name="hToken">handle to token, if NULL a local current user handle
/// will be inquired...</param>
/// <returns>true is returned if process is elevated</returns>
bool SystemUser::IsProcessElevated(HANDLE hToken)
{
   TCHAR *func = _T("SystemUser::IsProcessElevated: Failed");
   SystemUser sysUser;
   HANDLE hLocalToken = hToken;

   // get token if none was provided
   if (hLocalToken == NULL)
   {
      if (!sysUser.GetCurrentUserToken())
         throw func;
      hLocalToken = sysUser.GetTokenHandle();
   }

   // get token info...
   bool isElevated = false;
   TOKEN_ELEVATION elevation;
   DWORD cbSize = sizeof(TOKEN_ELEVATION);

   if (GetTokenInformation(
      hLocalToken,TokenElevation,&elevation,sizeof(elevation),&cbSize))
      isElevated = elevation.TokenIsElevated == TRUE;

   // release the local token handle if needed...
   if (hToken == NULL)
      sysUser.Dispose();

   return isElevated;
}  // end of IsProcessElevated

// -----------------------------------------------------------------------------

/// <summary>Get current process elevation type...</summary>
/// <param name="hToken">handle to token, if NULL a local current user handle
/// will be inquired...</param>
/// <returns>true is returned if process elevation type, else -1</returns>
TOKEN_ELEVATION_TYPE SystemUser::GetProcessElevationType(HANDLE hToken)
{
   TCHAR *func = _T("SystemUser::GetProcessElevationType: Failed");
   SystemUser sysUser;
   HANDLE hLocalToken = hToken;

   // get token if none was provided
   if (hLocalToken == NULL)
   {
      if (!sysUser.GetCurrentUserToken())
         throw func;
      hLocalToken = sysUser.GetTokenHandle();
   }

   // get token info...
   TOKEN_ELEVATION_TYPE eType = (TOKEN_ELEVATION_TYPE)-1, elevationType;
   DWORD cbSize = sizeof(TOKEN_ELEVATION_TYPE);

   if (GetTokenInformation(
      hLocalToken,TokenElevationType,&elevationType,
      sizeof(elevationType),&cbSize))
      eType = elevationType;

   // release the local token handle if needed...
   if (hToken == NULL)
      sysUser.Dispose();

   return eType;
}  // end of GetProcessElevationType

// -----------------------------------------------------------------------------

/// <summary>Execute given command as an administrator</summary>
/// <param name="commandPath">command path</param>
/// <param name="parameters">parameters</param>
void SystemUser::ExecuteAsAdministrator(TCHAR *commandPath, TCHAR *parameters)
{
   HINSTANCE h = ShellExecute(
      0,              // HWND - Parent Windows Handle
      _T("runas"),    // lpOperation - action
      commandPath,    // command path
      parameters,     // command parameters
      NULL,           // LPCWSTR lpDirectory
      SW_SHOWNORMAL);
}  // end of ExecuteAsAdministrator

}  // end of namespace Kif::Win32::System
}  // end of namespace Kif::Win32
}  // end of namespace Kif

